package api.service;

import api.model.ApiMigration;
import api.model.ApiMigrationRecord;
import api.model.ApiMigrationTable;
import api.util.ApiMigrationInterUtil;
import api.util.ApiMigrationSendProgress;
import com.alibaba.fastjson.JSONArray;
import m.common.model.MigrationModel;
import m.common.model.Model;
import m.common.model.config.ModelConfig;
import m.common.model.util.ModelQueryCheck;
import m.common.model.util.ModelUpdate;
import m.common.model.util.ModelUpdateUtil;
import m.common.model.util.QueryCondition;
import m.common.service.Service;
import m.system.db.TransactionManager;
import m.system.exception.MException;
import m.system.util.*;

import java.util.ArrayList;
import java.util.List;

public class ApiMigrationService extends Service {
    public String save(ApiMigration model) throws Exception {
        ModelQueryCheck.init(model)
            .checkNotNull("description","描述不能为空")
            .checkNotNull("serverUrl","服务地址不能为空")
            .checkNotNull("param","迁移参数不能为空")
            .checkNotNull("threadNum","进程数量不能为空")
            .checkNumberRange("threadNum",1D,100D,"进程数量超出范围（1-100）")
            .checkNotNull("authId","鉴权id不能为空")
            .checkNotNull("authKey","鉴权key不能为空")
            .doCheck(false,true);
        String msg;
        if(ObjectUtil.isEmptyOid(model)){
            model.setOid(GenerateID.generatePrimaryKey());
            model.setStatus(ApiMigration.Status_Edit);
            ModelUpdateUtil.insertModel(model);
            msg="保存成功";
        }else{
            ModelQueryCheck.init(ApiMigration.class,model.getOid())
                .checkStrIn("status",new String[]{ApiMigration.Status_Edit,ApiMigration.Status_Check_Done,ApiMigration.Status_Error},"状态错误，无法保存。")
                .doCheck();
            model.setStatus(ApiMigration.Status_Edit);
            ModelUpdateUtil.updateModel(model,"status","param","description","serverUrl","verifyOid","authId","authKey","threadNum");
            msg="修改成功";
        }
        return msg;
    }
    public void delete(ApiMigration model) throws Exception {
        ModelQueryCheck.init(ApiMigration.class,model.getOid())
            .checkStrIn("status",new String[]{ApiMigration.Status_Edit,ApiMigration.Status_Error},"暂存和错误的才能删除")
            .doCheck();
        ModelUpdateUtil.delete(ApiMigrationTable.class, QueryCondition.eq("migration.oid",model.getOid()));
        ModelUpdateUtil.delete(ApiMigrationRecord.class,QueryCondition.eq("migration.oid",model.getOid()));
        ModelUpdateUtil.deleteModel(model);
    }
    public void check(ApiMigration model) throws Exception {
        ModelUpdateUtil.delete(ApiMigrationTable.class, QueryCondition.eq("migration.oid",model.getOid()));
        ModelUpdateUtil.delete(ApiMigrationRecord.class,QueryCondition.eq("migration.oid",model.getOid()));
        List<Class<? extends Model>> classList=ModelConfig.getTableList();
        List<ApiMigrationTable> tableList=new ArrayList<>();
        List<ApiMigrationRecord> recordList=new ArrayList<>();
        List<String> verifyErrorTable=new ArrayList<>();
        for(Class<? extends Model> clazz : classList){
            if(MigrationModel.class.isAssignableFrom(clazz)){
                List<String> ls=((MigrationModel)ClassUtil.newInstance(clazz)).migrationOidList(model.getParam());
                if(ls.isEmpty()) continue;
                ApiMigrationTable table=new ApiMigrationTable();
                table.setOid(GenerateID.generatePrimaryKey());
                table.setMigration(model);
                table.setTableClass(clazz.getName());
                table.setTableDesc(ModelConfig.getTableMeta(clazz).description());
                tableList.add(table);
                for(String oid : ls){
                    ApiMigrationRecord record=new ApiMigrationRecord();
                    record.setOid(GenerateID.generatePrimaryKey());
                    record.setMigration(model);
                    record.setTable(table);
                    record.setModelOid(oid);
                    record.setStatus(ApiMigrationRecord.Status_No);
                    recordList.add(record);
                }
                List<String> verifyOidList=ApiMigration.Verify_Oid_Yes.equals(model.getVerifyOid())?ls:new ArrayList<>();
                JSONMessage json= new ApiMigrationInterUtil(model).verifyModel(table.getTableClass(),verifyOidList);
                if(!json.isSuccess()){
                    if(null!=json.get("error")){
                        verifyErrorTable.add(table.getTableDesc()+"已存在oid["+ArrayUtil.connection(json.get(JSONArray.class,"error").toArray(),",")+"]");
                    }else {
                        verifyErrorTable.add(table.getTableDesc() + ":" + json.getMessage());
                    }
                }
            }
        }
        if(tableList.isEmpty()) throw new MException(this.getClass(),"没有定义可迁移的模型");
        if(recordList.isEmpty()) throw new MException(this.getClass(),"没有可迁移的数据");
        if(!verifyErrorTable.isEmpty()) throw new MException(this.getClass(),"存在"+verifyErrorTable.size()+"表校验错误（"+ArrayUtil.connection(verifyErrorTable.toArray(new String[0]),",")+"）");
        ModelUpdateUtil.insertModels(tableList.toArray(new ApiMigrationTable[0]));
        ModelUpdateUtil.insertModels(recordList.toArray(new ApiMigrationRecord[0]));
        for(ApiMigrationTable table : tableList){
            ModelUpdate.init(ApiMigrationTable.class)
                .set("recordNum", ApiMigrationRecord.class,"count(1)",QueryCondition.eq("table.oid",table.getOid()))
                .set("successNum",0)
                .set("errorNum",0)
                .set("exeProgress",0)
                .execute(table.getOid());
        }
        ModelUpdate.init(ApiMigration.class)
            .set("recordNum",ApiMigrationTable.class,"sum(#{recordNum})",QueryCondition.eq("migration.oid",model.getOid()))
            .set("successNum",0)
            .set("errorNum",0)
            .set("exeProgress",0)
            .set("status",ApiMigration.Status_Check_Done)
            .set("errorMessage",null)
            .execute(model.getOid());
    }
    public void startMigration(String modelOid) throws Exception {
        ApiMigration model=ModelQueryCheck.init(ApiMigration.class,modelOid)
                .checkStrIn("status",new String[]{ApiMigration.Status_Check_Done,ApiMigration.Status_Migration_Stop},"当前状态不能启动迁移")
                .getModel(true,"*");
        model.setStatus(ApiMigration.Status_Migration);
        ModelUpdateUtil.updateModel(model,"status");
        new Thread(() -> {
            try {
                //执行迁移进度
                new ApiMigrationSendProgress(model.getOid()).execute();
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                TransactionManager.closeConnection();
            }
        }).start();
    }
    public void stopMigration(String modelOid) throws Exception {
        ModelQueryCheck.init(ApiMigration.class,modelOid)
                .checkStrIn("status",new String[]{ApiMigration.Status_Migration},"迁移中状态才能暂停迁移")
                .doCheck();
        ApiMigration model=new ApiMigration();
        model.setOid(modelOid);
        model.setStatus(ApiMigration.Status_Migration_Stop);
        ModelUpdateUtil.updateModel(model,"status");
    }
}
